package baseFx.tests.serialization.json;

import baseFx.common.Dynamic;
import baseFx.serialization.json.Json;
import baseFx.serialization.json.JsonUtils;
import baseFx.serialization.json.LongFormat;
import baseFx.serialization.json.jackson.JacksonImpl;
import org.junit.Assert;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.*;

public class JsonTest {
    private Json impl = new JacksonImpl();

    @Test
    public void 长度大于16位的数字会变成字符串() {
        TestModel model = new TestModel();
        model.long_value = 99999999999999999L;
        model.decimal_value = new BigDecimal(88888888888888888L);
        model.int_value = 123456;
        model.double_value = 123.456;
        String json = impl.toJson(model);
        System.out.println(json);
        Assert.assertTrue(json.contains("\"99999999999999999\""));
        Assert.assertTrue(json.contains("\"88888888888888888\""));
        Assert.assertFalse(json.contains("\"123456\""));
        Assert.assertFalse(json.contains("\"123.456\""));
    }

    @Test
    public void 能够解析Id结构的枚举() {
        TestModel model = new TestModel();
        model.idEnum_value_2 = TestIdEnum.B;
        model.enum_value = TestEnum.C;
        String json = impl.toJson(model);
        System.out.println(json);
        TestModel restore = impl.toObject(json, TestModel.class);
        Assert.assertTrue(json.contains(String.valueOf(TestIdEnum.B.id)));
        Assert.assertTrue(json.contains(TestEnum.C.name()));
        Assert.assertEquals(restore.idEnum_value, model.idEnum_value);
        Assert.assertEquals(restore.enum_value, model.enum_value);
    }

    @Test
    public void 时间用时间戳表示() {
        long time = System.currentTimeMillis();
        TestModel model = new TestModel();
        model.date_value = new Date(time);
        String json = impl.toJson(model);
        System.out.println(json);
        TestModel restore = impl.toObject(json, TestModel.class);
        Assert.assertTrue(json.contains(String.valueOf(time)));
        Assert.assertEquals(time, restore.date_value.getTime());
    }

    @Test
    public void 序列化集合() {
        TestModel model_1 = new TestModel();
        model_1.string_value = "zhangsan";
        TestModel model_2 = new TestModel();
        model_2.string_value = "lisi";
        List<TestModel> list = Arrays.asList(model_1, model_2);
        String json = impl.toJson(list);
        System.out.println(json);
        List<TestModel> restore = impl.toList(json, TestModel.class);
        Assert.assertEquals(restore.size(), 2);
        Assert.assertEquals(restore.get(1).string_value, model_2.string_value);
    }

    @Test
    public void 根据path获取对象() {
        TestModel model_1 = new TestModel();
        model_1.string_value = "zhangsan";
        TestModel model_2 = new TestModel();
        model_2.string_value = "lisi";
        String json = impl.toJson(new Object() {
            public Object item = new Object() {
                public List<TestModel> list = Arrays.asList(model_1, model_2);
            };
        });
        System.out.println(json);
        String name = impl.toObject(json, "item.list[1].string_value", String.class);
        Assert.assertEquals(name, model_2.string_value);
    }

    @Test
    public void 根据path获取集合() {
        TestModel model_1 = new TestModel();
        model_1.string_value = "zhangsan";
        TestModel model_2 = new TestModel();
        model_2.string_value = "lisi";
        String json = impl.toJson(new Object() {
            public Object item = new Object() {
                public List<TestModel> list = Arrays.asList(model_1, model_2);
            };
        });
        List<TestModel> list = impl.toList(json, "item.list", TestModel.class);
        Assert.assertEquals(list.get(1).string_value, model_2.string_value);
    }

    @Test
    public void 序列化GetSet() {
        GetSetModel model = new GetSetModel();
        model.setId2(222);
        model.setName2("abcdef");
        String json = impl.toJson(model);
        System.out.println(json);
        GetSetModel restore = impl.toObject(json, GetSetModel.class);
        Assert.assertTrue(json.contains("name2"));
        Assert.assertTrue(json.contains(model.getName2()));
        Assert.assertEquals(restore.getId2(), model.getId2());
    }

    @Test
    public void 序列化匿名类() {
        String json = impl.toJson(new Object() {
            public int id = 1;
            public String name = "zhangsan";
            public Date time = new Date();
            private int noexists = 111;
        });
        System.out.println(json);
        Assert.assertTrue(json.contains("zhangsan"));
        Assert.assertFalse(json.contains("noexists"));
    }

    @Test
    public void 序列化没有默认构造函数的类() {
        NoConstructModel model = new NoConstructModel(13456, "wanglaowu");
        String json = impl.toJson(model);
        System.out.println(json);
        Assert.assertTrue(json.contains(String.valueOf(model.getId())));
        Assert.assertTrue(json.contains(model.getName()));
    }

    @Test
    public void 序列化只读属性() {
        ReadOnlyModel model = new ReadOnlyModel();
        String id = model.getId();
        String json = impl.toJson(model);
        System.out.println(json);
        Assert.assertTrue(json.contains(id));
    }

    @Test
    public void 忽略不存在的字段() {
        TestModel model = new TestModel();
        model.string_value = "zhangsan";
        model.int_value = 6666;
        String json = impl.toJson(model);
        Map map = impl.toObject(json, HashMap.class);
        map.put("bucunzai", "value");
        json = impl.toJson(map);
        TestModel restore = impl.toObject(json, TestModel.class);
        Assert.assertNotNull(restore);
        Assert.assertEquals(restore.string_value, model.string_value);
    }

    @Test
    public void 直接序列化枚举() {
        TestIdEnum e = TestIdEnum.B;
        String json = impl.toJson(e);
        System.out.println(json);
        TestIdEnum restore = impl.toObject(json, TestIdEnum.class);
        Assert.assertEquals(e, restore);
    }

    @Test
    public void 强制显示枚举名() {
        TestModel model = new TestModel();
        model.idEnum_value = TestIdEnum.B;
        model.idEnum_value_2 = TestIdEnum.A;
        String json = impl.toJson(model);
        Map map = impl.toObject(json, Map.class);
        Dynamic data = Dynamic.setNew(s -> {
            s.put("int_value", 0);
            s.put("double_value", 0.0);
            s.put("idEnum_value", JsonUtils.toJson(Dynamic.setNew(vs -> {
                vs.put("id", TestIdEnum.B.id);
                vs.put("name", TestIdEnum.B.toString());
            })));
            s.put("idEnum_value_2", TestIdEnum.A.id);
        });
        for (Object k : map.keySet()) {
            if ("idEnum_value".equals(k.toString())) {
                Map vMap = JsonUtils.toObject(json, "idEnum_value", Map.class);
                map.put(k, JsonUtils.toJson(vMap));
            }
            Assert.assertEquals(map.get(k), data.get(k.toString()));
        }
    }

    @Test
    public void 中文不乱码() {
        TestModel model = new TestModel();
        model.string_value = "中文字符串";
        String json = impl.toJson(model);
        Assert.assertTrue(json.contains(model.string_value));
    }

    @Test
    public void 可以处理Dynamic() {
        Map<String, String> map = new HashMap<>(8);
        map.put("aaa", "111");
        map.put("bbb", "222");
        Dynamic dy = new Dynamic(map);
        String rs1 = impl.toJson(map);
        String rs2 = impl.toJson(dy);
        Assert.assertEquals(rs1, rs2);

        Dynamic rs = impl.toObject(rs2, Dynamic.class);
        Assert.assertEquals(rs.getString("bbb"), map.get("bbb"));
    }

    @Test
    public void 反序列化时格式化long类型() {
        Map<String, Object> map = new HashMap<>(8);
        map.put("string_value", "ssss");
        map.put("l_num", 111);
        map.put("l_num_fmt", "12.345");
        String json = impl.toJson(map);
        TestModel tm = impl.toObject(json, TestModel.class);
        Assert.assertEquals(tm.l_num.toString(), "111");
        Assert.assertEquals(tm.l_num_fmt.toString(), "1235");
    }

    @Test
    public void 字段值转换失败不抛异常() {
        Map<String, Object> map = new HashMap<>(8);
        map.put("enum2", "w");
        String json = impl.toJson(map);
        TestModel tm = impl.toObject(json, TestModel.class);
        System.out.println(impl.toJson(tm));
    }
}
